package com.mes.schedule.algorithm;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Stack;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import com.mes.schedule.algorithm.iface.ITaskSFCalc;
import com.mes.schedule.domain.SCoTask;
import com.mes.schedule.domain.SOperationLink;
import com.mes.schedule.domain.SOperationTask;
import com.mes.schedule.domain.SPartTask;
import com.mes.schedule.domain.ScheduleScheme;

/**
 * 
 * @author lqm
 * 
 */
@Component("taskSFCalc")
public class TaskSFCalc  implements ITaskSFCalc{
	public static double SLACK_MAX = 999;
	private final static Log log = LogFactory.getLog(TaskSFCalc.class);

	public void calcSF(ScheduleScheme schedule) {
		// 是否继承主制车间的优先级
		if (schedule.getInheritCoTaskPriority()) {
			List<SOperationTask> operationTaskList = new ArrayList<SOperationTask>();
			for (SOperationTask sOperationTask : schedule
					.getAllOperationTaskMap().values()) {
				if("P450".equalsIgnoreCase(sOperationTask.getDrawingId()))
				{
					//log.info("aaaaaaaaaaaaaaaaaaaaaaaaaaaa");
				}
				// 协作任务不参与计算
				if (!(sOperationTask instanceof SCoTask))
					operationTaskList.add(sOperationTask);
				else {
					log.debug("协作任务不参与计算：" + sOperationTask);
				}

			}
			this.calcSF(operationTaskList, schedule.getAllPartTaskMap()
					.values());
		} else
			this.calcSF(schedule.getAllOperationTaskMap().values(), schedule
					.getAllPartTaskMap().values());

	}

	protected Date calcLateFinish(SOperationTask operationTask) {
		Set<SOperationLink> succLinkSet = operationTask.getSuccLinkSet();
		if (log.isDebugEnabled()) {
			if (operationTask.getTaskUid().equals(
					"d8e759cb-ccf8-456f-9463-a481f92b7ef4")) {
				log.debug("aaaa");
			}
		}
		Date dtLateFinish = operationTask.getLateFinish();
		if (dtLateFinish == null && succLinkSet != null
				&& succLinkSet.size() > 0) {
			for (SOperationLink link : succLinkSet) {
				SOperationTask so = link.getSuccOperationTask();
				// 增加对锁定任务的专门处理
				// lqm
				//如果锁定，计划开始不为空计划结束为空，则最晚结束为后续链接任务的计划开始；
				//而如果后置链接任务的计划开始早于本工序的最晚结束，则最晚结束为后续链接任务的计划开始
				if (so.getLocked() != null && so.getLocked() == 1) {
					if (so.getPlanStart() != null) {
						if (dtLateFinish == null) {
							dtLateFinish = so.getPlanStart();
						} else if (so.getPlanStart().before(dtLateFinish)) {
							dtLateFinish = so.getPlanStart();
						}
					}
				}

			}
		}
		// 其实callateFinish作为一个临时变量也可以
		// 以后再考虑这块的效率问题
		// lqm todo
		operationTask.setCalcLateFinish(dtLateFinish);
		return dtLateFinish;
	}

	public void initSF(ScheduleScheme schedule) {
		for (SPartTask partTask : schedule.getAllPartTaskMap().values()) {
			partTask.setSlackFactor(SLACK_MAX);
		}
		for (SOperationTask operationTask : schedule.getAllOperationTaskMap()
				.values()) {
			operationTask.setSlackFactor(SLACK_MAX);
			operationTask.setRemainWork(0d);
		}
	}

	 
	public void calcOperationTaskSF(
			Collection<? extends SOperationTask> operationTaskList) {
		List<SOperationTask> needCalList = new ArrayList<SOperationTask>();
		for (SOperationTask operationTask : operationTaskList) {
			// if(operationTask.getTaskUid().equals("d8e759cb-ccf8-456f-9463-a481f92b7ef4"))
			// {
			// log.debug("aaaaaaaa");
			// }
			if (log.isDebugEnabled()) {
				if (operationTask.getTaskUid().equals(
						"de27177b-bb77-4bb2-bc00-46efc901a013")) {
					// System.out.println("aaaaaaaaaaaaaaaa");
				}
			}
			Date calcLateFinish = this.calcLateFinish(operationTask);
			// 后续任务为空自动加入，为了增加没有交货期只需要计算makespan得情况
			if (calcLateFinish != null
					|| operationTask.getSuccLinkSet().isEmpty())
				needCalList.add(operationTask);

		}
		// 先算完lateFinish,再计算,因为中间会考虑其它因素的latefinish
		for (SOperationTask operationTask : needCalList) {

			this.calcSFForTimeSpot(operationTask);
		}

	}

	 
	public void calcPartTaskSF(Collection<SPartTask> partTaskList) {
		for (SPartTask partTask : partTaskList) {
			calcSF(partTask);
		}
	}

	public void calcSF(SPartTask partTask) {
		if (null == partTask.getEarlyStart())
			partTask.setEarlyStart(partTask.getScheme().getScheduleStart());
		partTask.setSlackFactor(SLACK_MAX);
		List<SOperationTask> ol = partTask.getOperationTaskList();
		if (ol.size() == 0)
			return;
		for (SOperationTask operationTask : ol) {
			operationTask.setSlackFactor(SLACK_MAX);
			operationTask.setRemainWork(0d);

		}
		if (ol != null && ol.size() > 0)
			ol.get(ol.size() - 1).setLateFinish(partTask.getLateFinish());
		this.calcOperationTaskSF(ol);
		partTask.setSlackFactor(ol.get(ol.size() - 1).getSlackFactor());

		// for (SOperationTask operationTask : partTask.getOperationTaskList())
		// {
		// operationTask.setSlackFactor(SLACK_MAX);
		// Date calcLateFinish = this.calcLateFinish(operationTask);
		// if (calcLateFinish != null)
		// this.calcSFForTimeSpot(operationTask, calcLateFinish);
		// }
		// calcSFForTimeSpot(partTask);
	}

	public void calcSFForTimeSpot(SPartTask partTask) {
		//
		// List<SOperationTask> operationTaskList = partTask
		// .getOperationTaskList();
		// for (SOperationTask operationTask : operationTaskList) {
		// if (null == operationTask.getSuccLinkSet()
		// || operationTask.getSuccLinkSet().isEmpty()) {
		// Date lateFinishDate = operationTask.getLateFinish();
		// if (partTask.getLateFinish() != null
		// && (null == lateFinishDate || lateFinishDate
		// .after(partTask.getLateFinish()))) {
		// operationTask.setControlFinish(partTask.getLateFinish());
		// calcSFForTimeSpot(operationTask);
		// operationTask.setControlFinish(lateFinishDate);
		// }
		// }
		// }
	}

	protected long getLinkLag(SOperationLink operationLink,
			SOperationTask operationTask) {
		long linkLagTemp = 0;
		try {
			switch (operationLink.getLinkType()) {
			case SOperationLink.LINKTYPE_FTS: {
				linkLagTemp = operationLink.getLinkLag();
				break;
			}
			case SOperationLink.LINKTYPE_STS: {
				linkLagTemp = (long) (operationLink.getLinkLag() - operationTask
						.getEstiTaskWork());
				break;
			}
			case SOperationLink.LINKTYPE_FTF: {
				linkLagTemp = (long) (operationLink.getLinkLag() - operationLink
						.getSuccOperationTask().getEstiTaskWork());
				break;
			}
			case SOperationLink.LINKTYPE_STF: {
				linkLagTemp = (long) (operationLink.getLinkLag()
						- operationTask.getEstiTaskWork() - operationLink
						.getSuccOperationTask().getEstiTaskWork());
				break;
			}
			default:
				break;
			}
		} catch (RuntimeException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		return linkLagTemp;
	}

	protected void calcSFForSingleOperationTask(SOperationTask timeSpotTask,
			Date calcLateFinish) {
		try {
			if(calcLateFinish==null)return;
			// 当前任务的松弛率
			double remainWorkTemp = 0;
			double slackTemp = 0;
			double remainTime = 0;
			remainWorkTemp = timeSpotTask.getEstiTaskWork();//工序时间
			remainTime = (calcLateFinish.getTime() - timeSpotTask.getScheme()
					.getScheduleStart().getTime()) / 60000;
			if (remainWorkTemp > 0) {
				slackTemp = calcSlactor(remainTime, remainWorkTemp);
				if (slackTemp < timeSpotTask.getSlackFactor())
					timeSpotTask.setSlackFactor(slackTemp);
			}
		} catch (RuntimeException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	/*
	 * 改进之一：最早开始影响松弛率 (non-Javadoc)
	 * 
	 * @see com.mes.schedule.algorithm.iface.ITaskSFCalc#calcSFForTimeSpot(com.mes.schedule.persistence.domain.SOperationTask)
	 */
	public void calcSFForTimeSpot(SOperationTask timeSpotTask) {
		log.debug("开始计算任务松弛率：calcSFForTimeSpot" + timeSpotTask);
		try {
			if (null == timeSpotTask)
				return;

			Set<SOperationLink> trackLinks = new HashSet<SOperationLink>();

			double remainWorkTemp = 0;

			if (log.isDebugEnabled()) {
				if (timeSpotTask.getTaskUid().equals(
						"807a715c-4df5-4938-9750-b895575968ef")) {
					log.info(timeSpotTask);
				}
			}
			Stack<SOperationLink> linkStack = new Stack<SOperationLink>();
			Stack<SOperationTask> taskStack = new Stack<SOperationTask>();
			timeSpotTask.setRemainWork(timeSpotTask.getEstiTaskWork());//estiTaskWork--工序时间=准备+单件*数量
			taskStack.push(timeSpotTask);
			if (null != timeSpotTask.getPredLinkSet()
					&& !timeSpotTask.getPredLinkSet().isEmpty()) {
				for (SOperationLink operationLinkTemp : timeSpotTask
						.getPredLinkSet()) {
					linkStack.push(operationLinkTemp);
				}
			} else {
				// 当前任务的松弛率
				calcSFForSingleOperationTask(timeSpotTask, timeSpotTask
						.getCalcLateFinish());
			}

			while (!linkStack.empty()) {
				SOperationLink operationLink = linkStack.pop();

				SOperationTask operationTask = operationLink
						.getPredOperationTask();
				if (operationTask == null)
					continue;

				// 对合批工序的考虑
				// 对这块的效果还未评价
				// 对timespottask是一个成组任务也还未加以考虑，这种情况好像不用考虑
				// todo
				if (operationTask.getGroupTask() != null)
					operationTask = operationTask.getGroupTask();
				//
				// // 中间里程碑优先
				// if(operationTask.getCalcLateFinish()!=null)
				// continue;
				//log.info("松弛率 "+operationTask.toFriendlyString());
				//			
				// 防止系统出现循环链接
				// 由于人工操作失误或者数据库中出现错误链接
				// 如果已经在计算堆栈中，则忽略此链接线，直接退出
				if (taskStack.contains(operationTask))
					continue;

				//
				// /*
				// * 这里都弹出设计得比较巧妙，一旦换一个链接，将 应该等该工序所有连接都计算完了在弹出
				// */
				while (!taskStack.empty()) {
					SOperationTask succOperationTask = operationLink
							.getSuccOperationTask();
					if (succOperationTask.getGroupTask() != null)
						succOperationTask = succOperationTask.getGroupTask();
					if (succOperationTask == taskStack.peek())
						break;
					taskStack.pop();
				}

				if (taskStack.empty()) {
					remainWorkTemp = operationTask.getEstiTaskWork();
				} else {
					long linkLagTemp = this.getLinkLag(operationLink,
							operationTask);
					remainWorkTemp = operationTask.getEstiTaskWork()
							+ linkLagTemp + taskStack.peek().getRemainWork();
				}

				// 只要不包含operationTask就要进行计算
				// 这个判断是存在问题的，会导致某些分支根本不计算
				if (operationTask.getRemainWork() <= remainWorkTemp) {
					operationTask.setRemainWork(remainWorkTemp);
				}
				if (null == operationTask.getPredLinkSet()
						|| operationTask.getPredLinkSet().isEmpty()
						|| operationTask.getLocked().equals(1)) {
					this.calcSlactor(operationTask, taskStack, timeSpotTask);

				} else {
					if(!taskStack.contains(operationTask))
					{
						taskStack.push(operationTask);
						if (operationTask.getTaskUid().equals(
								"1befb5b5-386b-4922-b70f-20bceb188e79")) {
							log.debug("aaaaaaaaaaaaaaaa");
						}
						for (SOperationLink tmp : operationTask.getPredLinkSet()) {
							// lqm todo
							// 一个timesport中，一次迭代只能经过一个链接一次
							// 也不知这个假设是否合道理--这个假设肯定错误
							// if(!trackLinks.contains(tmp))
							// {
							// //暂时屏蔽
							// //trackLinks.add(tmp);
							if(!linkStack.contains(tmp))
							linkStack.push(tmp);
						}
					}
				}
				// }

			}
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		log.debug("结束计算任务松弛率：calcSFForTimeSpot");
	}

	protected void calcSlactor(SOperationTask operationTask,
			Collection<SOperationTask> taskStack, SOperationTask timeSpotTask) {
		if (timeSpotTask.getCalcLateFinish() == null) return;
			double slackTemp = 0;
			double remainTime = 0;

			long currentTime = timeSpotTask.getScheme()
					.getScheduleCurrentTime().getTime();
			if (log.isDebugEnabled()) {
//				if (timeSpotTask.getParentTaskUid().equals(
//						"c26d584b-ad23-43c1-b598-577b80fd097c")) {
//					// System.out.println("aaaaaaaaaaaaaaaa");
//				}
			}

			if (operationTask.getLocked().equals(1)
					&& operationTask.getPlanStart() != null) {
				// 从锁定时间之后开始计算
				remainTime = (timeSpotTask.getCalcLateFinish().getTime() - operationTask
						.getPlanStart().getTime()) / 60000;
			} else {
				remainTime = (timeSpotTask.getCalcLateFinish().getTime() - currentTime) / 60000;
			}
			slackTemp = calcSlactor(remainTime, operationTask.getRemainWork());
		
		setSlackFactor(operationTask,slackTemp);
		if(taskStack!=null&&!taskStack.isEmpty())
		{
			for (SOperationTask tmp : taskStack) {
				setSlackFactor(tmp,slackTemp);

			}
		}
	}
	
	private void setSlackFactor(SOperationTask operationTask,double slackTemp)
	{
		if (operationTask.getGroupTask() != null)
			operationTask = operationTask.getGroupTask();
		
		if (operationTask.getSlackFactor() == null
				|| operationTask.getSlackFactor() > slackTemp)
			operationTask.setSlackFactor(slackTemp);
		
		
	}

	public double calcSlactor(double remainTime, double remainWork)

	{
		double slackTemp = SLACK_MAX;
		if (remainWork > 0) {
			if (remainTime >= 0)
				slackTemp = remainTime / remainWork;
			else
				slackTemp = (remainTime - remainWork) / 1440;// 如果拖期了，就用拖期的天数
		}
		return slackTemp;
	}

	 
	public void calcScheduleSF(ScheduleScheme schedule) {
		log.debug("开始计算任务松弛率calcScheduleSF ");
		long lStart = System.currentTimeMillis();
		// 是否继承主制车间的优先级
		if (schedule.getInheritCoTaskPriority()) {
			List<SOperationTask> operationTaskList = new ArrayList<SOperationTask>();
			for (SOperationTask sOperationTask : schedule
					.getScheduleOperationTasks()) {
				if("P450".equalsIgnoreCase(sOperationTask.getDrawingId()))
				{
					//log.info("aaaaaaaaaaaaaaaaaaaaaaaaaaaa");
				}
				// 协作任务不参与计算
				if (!(sOperationTask instanceof SCoTask))
					operationTaskList.add(sOperationTask);

			}
			this.calcSF(operationTaskList, schedule.getSchedulePartTasks());
		} else
			this.calcSF(schedule.getScheduleOperationTasks(), schedule
					.getSchedulePartTasks());

		long lEnd = System.currentTimeMillis();
		long diff = (lEnd - lStart) / 1000;// 得到两者的毫秒数

		log.debug("本次计算松弛率结束！用时  " + diff + "  秒");

	}

	 
	public void calcSF(Collection<? extends SOperationTask> operationTaskList,
			Collection<SPartTask> partTaskList) {
		log.debug("开始计算工序任务集合松弛率calcSF");
		for (SPartTask partTask : partTaskList) {
			partTask.setSlackFactor(SLACK_MAX);
		}
		for (SOperationTask operationTask : operationTaskList) {
			operationTask.setSlackFactor(SLACK_MAX);

			operationTask.setRemainWork(0d);
		}
		// calcPartTaskSF(schedule.getAllPartTaskMap().values());
		// calcOperationTaskSF(schedule.getScheduleTempTaskList());
		//赋值最后道工序任务的交货期为零件交货期
		for (SPartTask partTask : partTaskList) {
			List<SOperationTask> ol = partTask.getOperationTaskList();
			if (ol != null && ol.size() > 0)
				ol.get(ol.size() - 1).setLateFinish(partTask.getLateFinish());
		}

		// List<SOperationTask> scheduleOperationTaskList =;

		// for (SOperationTask operationTask : scheduleOperationTaskList) {
		// if (operationTask.getLateFinish() != null)
		// operationTask.setControlFinish(operationTask.getLateFinish());
		// // Date dtCoPlanFinish = operationTask.getCoPlanFinish();
		// // if (dtCoPlanFinish != null) {
		// // Date dtLateFinish = getCoTaskLateFinish(operationTask);
		// // if (dtLateFinish != null&&dtCoPlanFinish.after(dtLateFinish)) {
		// // long lt = (long) (dtCoPlanFinish.getTime() -
		// (dtCoPlanFinish.getTime()-dtLateFinish
		// // .getTime()) * 0.618);
		// // operationTask.setControlFinish(new Date(lt));
		// // }
		// // }
		//
		// }

		calcOperationTaskSF(operationTaskList);

		for (SPartTask partTask : partTaskList) {
			List<SOperationTask> ol = partTask.getOperationTaskList();
			if (ol != null && ol.size() > 0) {
				// 取第一道工序的松弛
				// partTask.setSlackFactor(ol.get(0).getSlackFactor());
				// 取最后一个工序的松弛，让零件的松弛不随中间瓶颈和里程碑
				partTask.setSlackFactor(ol.get(ol.size() - 1).getSlackFactor());
			}

		}

		log.debug("结束计算工序任务集合松弛率calcSF");

	}

	public void calTaskScope(Collection<? extends SOperationTask> operationTasks) {
	}

	 
	public void calcTaskEarlyStart(
			Collection<? extends SOperationTask> operationTasks) {
		// TODO Auto-generated method stub

	}

	 
	public void calcTaskScope(
			Collection<? extends SOperationTask> operationTasks) {
		// TODO Auto-generated method stub

	}

	//	
	// public void calcSFForTimeSpot(SOperationTask timeSpotTask) {
	// if (null == timeSpotTask || null == timeSpotTask.getLateFinish())
	// return;
	// double remainWorkTemp = 0;
	// double slackTemp = 0;
	// double remainTime = 0;
	// Map<SOperationTask, Double> remainWorkMap = new HashMap<SOperationTask,
	// Double>();
	// Stack<SOperationLink> linkStack = new Stack<SOperationLink>();
	// Stack<SOperationTask> taskStack = new Stack<SOperationTask>();
	// remainWorkMap.put(timeSpotTask, timeSpotTask.getEstiTaskWork());
	// taskStack.push(timeSpotTask);
	// if (null != timeSpotTask.getPredLinkSet()
	// && !timeSpotTask.getPredLinkSet().isEmpty()) {
	// for (SOperationLink operationLinkTemp: timeSpotTask.getPredLinkSet()) {
	// linkStack.push(operationLinkTemp);
	// }
	// } else {
	// //当前任务的松弛率
	// remainWorkTemp = timeSpotTask.getEstiTaskWork();
	// if (null == timeSpotTask.getEarlyStart())
	// remainTime = (timeSpotTask.getLateFinish().getTime() - timeSpotTask
	// .getScheme().getScheduleStart().getTime()) / 60000;
	// else
	// remainTime = (timeSpotTask.getLateFinish().getTime() - Math
	// .max(timeSpotTask.getScheme().getScheduleStart()
	// .getTime(), timeSpotTask.getEarlyStart()
	// .getTime())) / 60000;
	// if(remainWorkTemp>0)
	// {
	// slackTemp = (remainTime - remainWorkTemp) / remainWorkTemp;
	// if (slackTemp < timeSpotTask.getSlackFactor())
	// timeSpotTask.setSlackFactor(slackTemp);
	// }
	// }
	//
	// while (!linkStack.empty()) {
	// SOperationLink operationLink = linkStack.pop();
	// SOperationTask operationTask = operationLink.getPredOperationTask();
	//
	// while (operationLink.getSuccOperationTask() != taskStack.peek()
	// && !taskStack.empty()) {
	// taskStack.pop();
	// }
	//
	// long linkLagTemp =this.getLinkLag(operationLink, operationTask);
	//
	// if (taskStack.empty()) {
	// remainWorkTemp = operationTask.getEstiTaskWork();
	// } else {
	// remainWorkTemp = operationTask.getEstiTaskWork() + linkLagTemp
	// + remainWorkMap.get(taskStack.peek());
	// }
	// if (remainWorkMap.containsKey(operationTask)
	// && remainWorkTemp > remainWorkMap.get(operationTask)) {
	// remainWorkMap.remove(operationTask);
	// }
	// if (!remainWorkMap.containsKey(operationTask)) {
	// remainWorkMap.put(operationTask, remainWorkTemp);
	// taskStack.push(operationTask);
	// if (null == operationTask.getPredLinkSet()
	// || operationTask.getPredLinkSet().isEmpty()
	// || operationTask.getEarlyStart() != null) {
	// if (null == operationTask.getEarlyStart()
	// || null != operationTask.getEarlyStart()
	// && operationTask.getScheme().getScheduleStart()
	// .after(operationTask.getEarlyStart())) {
	// remainTime = (timeSpotTask.getLateFinish().getTime() - operationTask
	// .getScheme().getScheduleStart().getTime()) / 60000;
	// } else {
	// remainTime = (timeSpotTask.getLateFinish().getTime() - operationTask
	// .getEarlyStart().getTime()) / 60000;
	// }
	// slackTemp = (remainTime - remainWorkTemp) / remainWorkTemp;
	// for (Iterator iterator = taskStack.iterator(); iterator
	// .hasNext();) {
	// SOperationTask name = (SOperationTask) iterator.next();
	// if (name.getSlackFactor() > slackTemp)
	// name.setSlackFactor(slackTemp);
	// }
	// }
	// if (null != operationTask.getPredLinkSet()) {
	// for (SOperationLink name:operationTask.getPredLinkSet()) {
	// linkStack.push(name);
	// }
	// }
	// }
	// }
	// }
}